home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / BUS / BibTeX 1.06 FAT.sit / BibTeX ƒ / Source code / StdPrefsLib / StdPrefsLib.c < prev    next >
Text File  |  1995-10-23  |  34KB  |  1,330 lines

  1. /*
  2.     File:        StdPrefsLib.c
  3.  
  4.     Contains:    Standard preferences library routines.
  5.  
  6.                 Refer to develop Issue 18, "The Right Way to Implement 
  7.                 Preferences Files", for additional details on this code.
  8.                 
  9.     Written by:    Gary Woodcock
  10.  
  11.     Copyright:    ゥ 1993-94 by Apple Computer, Inc.
  12.  
  13.     Change History (most recent first):
  14.     
  15.                   3/3/94    Version 1.0.
  16.     
  17.     Notes:         This code uses Apple's Universal Interfaces for C.
  18.     
  19.                 Send bug reports to Gary Woodcock at AOL: gwoodcock
  20.                 or Internet: gwoodcock@aol.com.
  21. */
  22.  
  23. //-----------------------------------------------------------------------
  24. // Includes
  25.  
  26. #include "CompileFlags.h"
  27.  
  28. #include "StdPrefsLib.h"
  29. #include "StdPrefsLibPrivate.h"
  30. #include "DebugUtils.h"
  31. #include "FSpCompat.h"
  32. #include "MoreFilesExtras.h"
  33. #include "Search.h"
  34.  
  35. #include <Errors.h>
  36. #include <Files.h>
  37. #include <Finder.h>
  38. #include <Folders.h>
  39. #include <Memory.h>
  40. #include <Resources.h>
  41. #include <Script.h>
  42. // #include <SysEqu.h>
  43. #include <ToolUtils.h>
  44.  
  45. //-----------------------------------------------------------------------
  46. // Private constants
  47.  
  48. enum
  49. {
  50.     kApplicationMissingMessageStrID = -16397
  51. };
  52.  
  53. //-----------------------------------------------------------------------
  54. // Private prototypes
  55.  
  56. static OSErr
  57. GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName, 
  58.     Boolean createFolder, short *vRefNum, long *dirID);
  59.     
  60. static OSErr
  61. GetPreferencesFileFSSpec (OSType creator, OSType fileType,
  62.     FSSpec *file);
  63.  
  64. static Boolean
  65. DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID);
  66.     
  67. static short
  68. FindVRefNum (short fRefNum);
  69.  
  70. static unsigned long
  71. GetVolFreeSpace (short vRefNum);
  72.  
  73. static unsigned long
  74. GetVAllocationBlockSize (short vRefNum);
  75.  
  76. static OSErr
  77. GetDirPathName (short vRefNum, long dirID, Str255 pathName);
  78.  
  79. static OSErr
  80. CopyString (ConstStr255Param theSourceStr, Str255 theDestStr);
  81.  
  82. static OSErr
  83. CatenateStrings (ConstStr255Param theFirstStr, 
  84.     ConstStr255Param theSecondStr, Str255 theCatenatedStr);
  85.  
  86. static OSErr
  87. CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo);
  88.  
  89. //-----------------------------------------------------------------------
  90.  
  91. pascal OSErr
  92. NewPreferencesFile (OSType creator, OSType fileType,
  93.     ConstStr31Param fileName, ConstStr31Param folderName, 
  94.     ConstStr31Param ownerName)
  95. {
  96.     OSErr    result = noErr;
  97.     
  98.     // Make sure parameters are valid
  99.     if (fileName != nil)
  100.     {
  101.         long    dirID;
  102.         short    vRefNum;
  103.         
  104.         // Get the vRefNum and dirID for the folder to put the preferences file in
  105.         result = GetPrefsDirVRefNumAndDirID (folderName, true, &vRefNum, &dirID);
  106.         if (result == noErr)
  107.         {
  108.             short    savedResFile = CurResFile();
  109.  
  110.             // Create the file
  111.             HCreateResFile (vRefNum, dirID, fileName);
  112.             result = ResError();
  113.             if (result == noErr)
  114.             {
  115.                 FInfo    info;
  116.                 
  117.                 // Set the file type and creator, and lock the name
  118.                 result = HGetFInfo (vRefNum, dirID, fileName, &info);
  119.                 if (result == noErr)
  120.                 {
  121.                     info.fdType = fileType;
  122.                     info.fdCreator = creator;
  123.                     info.fdFlags |= kNameLocked;
  124.                     result = HSetFInfo (vRefNum, dirID, fileName, &info);
  125.                     if (result == noErr)
  126.                     {
  127.                         // Should we add an application-missing message string?
  128.                         if (ownerName != nil)
  129.                         {
  130.                             Str255    preamble;
  131.                             Str255    postamble;
  132.                                 
  133.                             // Build the application-missing message string
  134.                             GetIndString (preamble, kStdPrefsLibStrsID, kPreambleStrID);
  135.                             GetIndString (postamble, kStdPrefsLibStrsID, kPostambleStrID);
  136.                                         
  137.                             if ((preamble != nil) && (postamble != nil))
  138.                             {
  139.                                 result = CatenateStrings (preamble, *((Str255 *)ownerName), preamble);
  140.                                 if (result == noErr)
  141.                                 {
  142.                                     result = CatenateStrings (preamble, postamble, preamble);
  143.                                     if (result == noErr)
  144.                                     {
  145.                                         short    fRefNum;
  146.                                         
  147.                                         // Open the new file
  148.                                         result = OpenPreferencesFile (creator, fileType, &fRefNum);
  149.                                         if (result == noErr)
  150.                                         {
  151.                                             Handle    messageHdl;
  152.                                             
  153.                                             // Add the application-missing message string
  154.                                             PtrToHand ((Ptr)&preamble, &messageHdl, preamble[0] + 1);
  155.                                             if ((result = MemError()) == noErr)
  156.                                             {
  157.                                                 short    resID = kApplicationMissingMessageStrID;
  158.                                                 
  159.                                                 result = WritePreference (fRefNum, 'STR ', &resID, messageHdl);
  160.                                                 DisposeHandle (messageHdl);
  161.                                                 result = MemError();
  162.                                                 FailMessage (result != noErr, NewPreferencesFile: DisposeHandle failed.);
  163.                                             }
  164.                                             else
  165.                                             {
  166.                                                 DebugMessage (NewPreferencesFile: PtrToHand failed.);
  167.                                             }
  168.                                             
  169.                                             // Close up shop
  170.                                             result = ClosePreferencesFile (fRefNum);
  171.                                         }
  172.                                     }
  173.                                 }
  174.                             }
  175.                             else    // GetIndString failed
  176.                             {
  177.                                 result = -1L;
  178.                                 DebugMessage (NewPreferencesFile: GetIndString failed.);
  179.                             }
  180.                         }
  181.                     }
  182.                     else    // HSetFInfo failed
  183.                     {
  184.                         DebugMessage (NewPreferencesFile: HSetFInfo failed.);
  185.                     }
  186.                 }
  187.                 else    // HGetFInfo failed
  188.                 {
  189.                     DebugMessage (NewPreferencesFile: HGetFInfo failed.);
  190.                 }
  191.             }
  192.             else    // HCreateResFile failed
  193.             {
  194.                 DebugMessage (NewPreferencesFile: HCreateResFile failed.);
  195.             }
  196.             
  197.             // Restore the resource file
  198.             UseResFile (savedResFile);
  199.             result = ResError();
  200.             FailMessage (result != noErr, NewPreferencesFile: UseResFile failed.);
  201.         }
  202.     }
  203.     else    // Bad parameter
  204.     {
  205.         result = paramErr;
  206.         DebugMessage (NewPreferencesFile: Bad parameter);
  207.     }
  208.     return (result);
  209. }
  210.  
  211. //-----------------------------------------------------------------------
  212.  
  213. pascal OSErr
  214. OpenPreferencesFile (OSType creator, OSType fileType, short *fRefNum)
  215. {
  216.     OSErr    result = noErr;
  217.     
  218.     // Make sure parameters are valid
  219.     if (fRefNum != nil)
  220.     {
  221.         FSSpec    prefsFSSpec;
  222.         short    savedResFile = CurResFile();
  223.         
  224.         // Get the FSSpec for the preferences file
  225.         result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  226.         if (result == noErr)
  227.         {
  228.             // Open it up
  229.             
  230.             short    theFRefNum = FSpOpenResFileCompat (&prefsFSSpec, fsRdWrPerm);
  231.             
  232.             result = ResError();
  233.             if (result == noErr)
  234.             {    
  235.                 *fRefNum = theFRefNum;
  236.                 
  237.                 // Restore the resource file
  238.                 UseResFile (savedResFile);
  239.                 result = ResError();
  240.                 FailMessage (result != noErr, OpenPreferencesFile: UseResFile failed.);
  241.             }
  242.             else    // FSpOpenResFileCompat failed
  243.             {
  244.                 DebugMessage (OpenPreferencesFile: FSpOpenResFileCompat failed.);
  245.             }
  246.         }
  247.     }
  248.     else    // Bad parameter
  249.     {
  250.         result = paramErr;
  251.         DebugMessage (OpenPreferencesFile: Bad parameter.);
  252.     }
  253.     return (result);
  254. }
  255.  
  256. //-----------------------------------------------------------------------
  257.  
  258. pascal OSErr
  259. ClosePreferencesFile (short fRefNum)
  260. {
  261.     OSErr    result = noErr;
  262.     
  263.     // Make sure parameters are valid
  264.     if (fRefNum != -1)
  265.     {
  266.         // Close it
  267.         CloseResFile (fRefNum);
  268.         result = ResError();
  269.         FailMessage (result != noErr, ClosePreferencesFile: CloseResFile failed.);
  270.     }
  271.     else    // Bad parameter
  272.     {
  273.         result = paramErr;
  274.         DebugMessage (ClosePreferencesFile: Bad parameter.);
  275.     }
  276.     return (result);
  277. }
  278.  
  279. //-----------------------------------------------------------------------
  280.  
  281. pascal OSErr
  282. DeletePreferencesFile (OSType creator, OSType fileType)
  283. {
  284.     FSSpec    prefsFSSpec;
  285.     OSErr    result;
  286.     
  287.     // Get the preferences file FSSpec
  288.     result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  289.     if (result == noErr)
  290.     {
  291.         // Delete it
  292.         result = FSpDeleteCompat (&prefsFSSpec);
  293.         FailMessage (result != noErr, DeletePreferencesFile: FSpDeleteCompat failed.);
  294.     }
  295.     return (result);
  296. }
  297.  
  298. //-----------------------------------------------------------------------
  299.  
  300. pascal OSErr
  301. DeletePreferencesFolder (ConstStr31Param folderName)
  302. {
  303.     OSErr    result = noErr;
  304.     
  305.     // Make sure the parameters are valid
  306.     if (folderName != nil)
  307.     {
  308.         long    dirID;
  309.         short    vRefNum;
  310.         
  311.         // Get the vRefNum and dirID of the preferences folder
  312.         result = GetPrefsDirVRefNumAndDirID (folderName, false, &vRefNum, &dirID);
  313.         if (result == noErr)
  314.         {
  315.             Str255    pathName;
  316.             
  317.             // Get the path to the folder
  318.             result = GetDirPathName (vRefNum, dirID, pathName);
  319.             if (result == noErr)
  320.             {
  321.                 // Delete it
  322.                 result = DeleteDirectory (vRefNum, dirID, (StringPtr)pathName);
  323.                 FailMessage (result != noErr, DeletePreferencesFolder: DeleteDirectory failed.);
  324.             }
  325.         }
  326.     }
  327.     else    // Bad parameter
  328.     {
  329.         result = paramErr;
  330.         DebugMessage (DeletePreferencesFolder: Bad parameter.);
  331.     }
  332.     return (result);
  333. }
  334.  
  335. //-----------------------------------------------------------------------
  336.  
  337. pascal Boolean
  338. PreferencesFileExists (OSType creator, OSType fileType)
  339. {
  340.     FSSpec    prefsFSSpec;
  341.     OSErr    result = noErr;
  342.     
  343.     // If file doesn't exist, fnfErr will be returned
  344.     result = GetPreferencesFileFSSpec (creator, fileType, &prefsFSSpec);
  345.     
  346.     return (result == noErr);
  347. }
  348.  
  349. //-----------------------------------------------------------------------
  350.  
  351. pascal OSErr
  352. GetPreferencesFileVersion (short fRefNum, short versID, 
  353.     NumVersion *numVersion, short *regionCode, 
  354.     ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
  355. {
  356.     OSErr    result = noErr;
  357.     
  358.     // Make sure parameters are valid
  359.     if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) && 
  360.         (numVersion != nil) && (regionCode != nil))
  361.     {
  362.         VersRecHndl    versHdl;
  363.         short        resID = versID;
  364.             
  365.         // Read the version resource
  366.         result = ReadPreference (fRefNum, 'vers', &resID, (Handle *)&versHdl);
  367.         if ((result == noErr) && (versHdl != nil))
  368.         {
  369.             *numVersion = (**versHdl).numericVersion;
  370.             *regionCode = (**versHdl).countryCode;
  371.             
  372.             // Note that the long version string is packed at the end of the
  373.             // short version string - this is the format for the 'vers'
  374.             // resource
  375.             BlockMoveData ((Ptr)((**versHdl).shortVersion), (Ptr)shortVersionStr,
  376.                 (**versHdl).shortVersion[0] + 1);
  377.             BlockMoveData ((Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]),
  378.                 (Ptr)longVersionStr, (**versHdl).shortVersion[shortVersionStr[0] + 1] + 1);
  379.                 
  380.             // Clean up
  381.             DisposeHandle ((Handle) versHdl);
  382.             result = MemError();
  383.             FailMessage (result != noErr, GetPreferencesFileVersion: DisposeHandle failed.);
  384.         }
  385.     }
  386.     else    // Bad parameter
  387.     {
  388.         result = paramErr;
  389.         DebugMessage (GetPreferencesFileVersion: Bad parameter.);
  390.     }
  391.     return (result);
  392. }
  393.  
  394. //-----------------------------------------------------------------------
  395.  
  396. pascal OSErr
  397. SetPreferencesFileVersion (short fRefNum, short versID, 
  398.     NumVersion *numVersion, short regionCode, 
  399.     ConstStr255Param shortVersionStr, ConstStr255Param longVersionStr)
  400. {
  401.     OSErr    result = noErr;
  402.     
  403.     // Make sure parameters are valid
  404.     if ((fRefNum != -1) && ((versID == kVers1) || (versID == kVers2)) && 
  405.         (numVersion != nil))
  406.     {
  407.         VersRecHndl    versHdl = (VersRecHndl) NewHandleClear (sizeof (VersRec));
  408.         
  409.         if (versHdl != nil)
  410.         {
  411.             short    resID = versID;
  412.             
  413.             (**versHdl).numericVersion = *numVersion;
  414.             (**versHdl).countryCode = regionCode;
  415.             
  416.             // Note that the long version string is packed at the end of the
  417.             // short version string - this is the format for the 'vers'
  418.             // resource
  419.             BlockMoveData ((Ptr)(shortVersionStr), (Ptr)((**versHdl).shortVersion),
  420.                 shortVersionStr[0] + 1);
  421.             BlockMoveData ((Ptr)(longVersionStr), 
  422.                 (Ptr)&((**versHdl).shortVersion[shortVersionStr[0] + 1]), 
  423.                 longVersionStr[0] + 1);
  424.                 
  425.             // Write the version resource
  426.             result = WritePreference (fRefNum, 'vers', &resID, (Handle) versHdl);
  427.         }
  428.         else    // Couldn't get any memory
  429.         {
  430.             result = MemError();
  431.             DebugMessage (SetPreferencesFileVersion: NewHandleClear failed.);
  432.         }
  433.     }
  434.     else    // Bad parameter
  435.     {
  436.         result = paramErr;
  437.         DebugMessage (SetPreferencesFileVersion: Bad parameter.);
  438.     }
  439.     return (result);
  440. }
  441.  
  442. //-----------------------------------------------------------------------
  443.  
  444. pascal OSErr
  445. ReadPreference (short fRefNum, ResType resourceType, short *resourceID, 
  446.     Handle *preference)
  447. {
  448.     OSErr    result = noErr;
  449.     
  450.     // Make sure parameters are valid
  451.     if ((fRefNum != -1) && (preference != nil))
  452.     {
  453.         short    savedResFile = CurResFile();    // Save off current resource file
  454.     
  455.         // Use this file
  456.         UseResFile (fRefNum);
  457.         result = ResError();
  458.         if (result == noErr)
  459.         {
  460.             // See if the resource is around
  461.             if ((resourceID != nil) && (*resourceID != 0))
  462.             {
  463.                 // Get the resource with the specified ID
  464.                 *preference = Get1Resource (resourceType, *resourceID);
  465.             }
  466.             else
  467.             {
  468.                 // Get the first resource of this type
  469.                 *preference = Get1IndResource (resourceType, 1);
  470.                 if ((*preference != nil) && (resourceID != nil))
  471.                 {
  472.                     Str255    dummy1;
  473.                     ResType    dummy2;
  474.                     
  475.                     // Get the resource ID
  476.                     GetResInfo (*preference, resourceID, &dummy2, dummy1);
  477.                 }
  478.             }
  479.  
  480.             // Did we get a resource successfully?
  481.             if (((result = ResError()) == noErr) && (*preference != nil))
  482.             {
  483.                 // Detach it
  484.                 DetachResource (*preference);
  485.                 result = ResError();
  486.                 FailMessage (result != noErr, ReadPreference: DetachResource failed.);
  487.             }
  488.             else    // Get1Resource failed
  489.             {    
  490.                 result = resNotFound;
  491.                 DebugMessage (ReadPreference: Get1Resource failed.);
  492.             }
  493.             
  494.             // Restore the resource file 
  495.             UseResFile (savedResFile);
  496.             result = ResError();
  497.             FailMessage (result != noErr, ReadPreference: UseResFile failed.);
  498.         }
  499.         else    // UseResFile failed
  500.         {
  501.             DebugMessage (ReadPreference: UseResFile failed.);
  502.         }
  503.     }
  504.     else    // Bad parameter
  505.     {
  506.         result = paramErr;
  507.         DebugMessage (ReadPreference: Bad parameter.);
  508.     }
  509.     return (result);
  510. }
  511.  
  512. //-----------------------------------------------------------------------
  513.  
  514. pascal OSErr
  515. WritePreference (short fRefNum, ResType resourceType, short *resourceID, 
  516.     Handle preference)
  517. {
  518.     OSErr    result = noErr;
  519.     
  520.     // Make sure parameters are valid
  521.     if ((fRefNum != -1) && (preference != nil))
  522.     {
  523.         Handle    localPref = preference;
  524.         
  525.         // Make a local copy of this preference
  526.         result = HandToHand (&localPref);
  527.         
  528.         if (result == noErr)
  529.         {
  530.             Handle    oldPref = nil;
  531.             Size    prefSize = GetHandleSize (localPref);    // Get size of preference to be added
  532.             Size    existingPrefSize = prefSize;
  533.             long    freeSpaceOnDisk;
  534.             short    vRefNum = FindVRefNum (fRefNum);
  535.             short    savedResFile = CurResFile();            // Save off current resource file
  536.             short    resID;
  537.             
  538.             // Get free disk space
  539.             freeSpaceOnDisk = GetVolFreeSpace (vRefNum);
  540.             
  541.             // Use this file
  542.             UseResFile (fRefNum);
  543.             result = ResError();
  544.             if (result == noErr)
  545.             {
  546.                 // See if this resource is already around
  547.                 if ((resourceID != nil) && (*resourceID != 0))
  548.                 {
  549.                     // Get the resource with the specified ID
  550.                     oldPref = Get1Resource (resourceType, *resourceID);
  551.                 }
  552.     
  553.                 // Did we find an existing resource?
  554.                 if (oldPref != nil)
  555.                 {
  556.                     // How big is it?
  557.                     existingPrefSize = GetHandleSize (oldPref);
  558.                     
  559.                     // Make sure that there's enough disk space available to
  560.                     // accomodate the resource that's replacing the old one -
  561.                     // if there's not, leave the old one in place, and return an error
  562.                     // We'll leave at least one allocation block left for the system
  563.                     if ((prefSize > existingPrefSize) && 
  564.                         (prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk))
  565.                     {
  566.                         result = dskFulErr;
  567.                         DebugMessage (WritePreference: Not enough disk space to write resource.);
  568.                     }
  569.                     else
  570.                     {
  571.                         // Get rid of it
  572.                         RemoveResource (oldPref);
  573.                         if ((result = ResError()) == noErr)
  574.                         {
  575.                             // Update the file
  576.                             UpdateResFile (fRefNum);
  577.                             result = ResError();
  578.                             FailMessage (result != noErr, WritePreference: UpdateResFile failed.);
  579.                         }
  580.                         else    // RmveResource failed
  581.                         {
  582.                             DebugMessage (WritePreference: RmveResource failed.);
  583.                         }
  584.                         
  585.                         // Clean up
  586.                         DisposeHandle (oldPref);
  587.                         result = MemError();
  588.                         FailMessage (result != noErr, WritePreference: DisposeHandle failed.);
  589.                     }
  590.                 }
  591.                 
  592.                 if (result == noErr)
  593.                 {
  594.                     // Make sure there's room
  595.                     if (prefSize + GetVAllocationBlockSize (FindVRefNum (fRefNum)) > freeSpaceOnDisk)
  596.                     {
  597.                         result = dskFulErr;
  598.                         DebugMessage (WritePreference: Not enough disk space to write resource.);
  599.                     }
  600.                     else
  601.                     {
  602.                         // Figure out the resource ID to use
  603.                         if (resourceID != nil)
  604.                         {
  605.                             if (*resourceID == 0)
  606.                             {
  607.                                 // Get a unique resource ID
  608.                                 resID = Unique1ID (resourceType);
  609.                                 *resourceID = resID;
  610.                             }
  611.                             else
  612.                             {
  613.                                 resID = *resourceID;
  614.                             }
  615.                         }
  616.                         else
  617.                         {
  618.                             // Get a unique resource ID
  619.                             resID = Unique1ID (resourceType);
  620.                         }
  621.             
  622.                         // Add the resource
  623.                         AddResource (localPref, resourceType, resID, "¥p");
  624.                         if ((result = ResError()) == noErr)
  625.                         {
  626.                             // Write it to the file
  627.                             WriteResource (localPref);
  628.                             FailMessage ((result = ResError()) != noErr, WritePreference: 
  629.                                 WriteResource failed.);
  630.                                 
  631.                             // Clean up
  632.                             ReleaseResource (localPref);
  633.                             FailMessage ((result = ResError()) != noErr, WritePreference: 
  634.                                 ReleaseResource failed.);
  635.                         }
  636.                         else    // AddResource failed
  637.                         {
  638.                             DebugMessage (WritePreference: AddResource failed.);
  639.                         }
  640.                     }
  641.                 }
  642.                 
  643.                 // Restore the resource file
  644.                 UseResFile (savedResFile);
  645.                 result = ResError();
  646.                 FailMessage (result != noErr, WritePreference: UseResFile failed.);
  647.             }
  648.             else    // UseResFile failed
  649.             {
  650.                 DebugMessage (WritePreference: UseResFile failed.);
  651.             }
  652.         }
  653.         else    // HandToHand failed
  654.         {
  655.             DebugMessage (WritePreference: HandToHand failed.);
  656.         }
  657.     }
  658.     else    // Bad parameter
  659.     {
  660.         result = paramErr;
  661.         DebugMessage (WritePreference: Bad parameter.);
  662.     }
  663.     return (result);
  664. }
  665.  
  666. //-----------------------------------------------------------------------
  667.  
  668. pascal OSErr
  669. DeletePreference (short fRefNum, ResType resourceType, short resourceID)
  670. {
  671.     OSErr    result = noErr;
  672.     
  673.     // Make sure parameters are valid
  674.     if (fRefNum != -1)
  675.     {
  676.         Handle    prefToKill;
  677.         short    savedResFile = CurResFile();    // Save off the current resource file
  678.         
  679.         // Use this file
  680.         UseResFile (fRefNum);
  681.         result = ResError();
  682.         if (result == noErr)
  683.         {
  684.             // Are there any of these resources around?
  685.             if (Count1Resources (resourceType) > 0)
  686.             {
  687.                 // See if this resource is around
  688.                 if (resourceID != 0)
  689.                 {
  690.                     // Get the resource with the specified ID
  691.                     prefToKill = Get1Resource (resourceType, resourceID);
  692.                 }
  693.                 else
  694.                 {
  695.                     // Get the first resource of this type
  696.                     prefToKill = Get1IndResource (resourceType, 1);
  697.                 }
  698.                 
  699.                 // Did we find a resource to delete?
  700.                 if (prefToKill != nil)
  701.                 {
  702.                     // Remove it
  703.                     RemoveResource (prefToKill);
  704.                     if ((result = ResError()) == noErr)
  705.                     {
  706.                         // Update the file
  707.                         UpdateResFile (fRefNum);
  708.                         FailMessage ((result = ResError()) != noErr, DeletePreference: 
  709.                             UpdateResFile failed.);
  710.                     }
  711.                     else    // RmveResource failed
  712.                     {
  713.                         DebugMessage (DeletePreference: RmveResource failed.);
  714.                     }
  715.                     
  716.                     // Clean up
  717.                     DisposeHandle (prefToKill);
  718.                     result = MemError();
  719.                     FailMessage (result != noErr, DeletePreference: DisposeHandle failed.);
  720.                 }
  721.             }
  722.             else    // Couldn't find this resource
  723.             {
  724.                 result = resNotFound;
  725.                 DebugMessage (DeletePreference: Resource not found.);
  726.             }
  727.             
  728.             // Restore the resource file
  729.             UseResFile (savedResFile);
  730.             result = ResError();
  731.             FailMessage (result != noErr, DeletePreference: UseResFile failed.);
  732.         }
  733.         else    // UseResFile failed
  734.         {
  735.             DebugMessage (DeletePreference: UseResFile failed.);
  736.         }
  737.     }
  738.     else    // Bad parameter
  739.     {
  740.         result = paramErr;
  741.         DebugMessage (DeletePreference: Bad parameter.);
  742.     }
  743.     return (result);
  744. }
  745.  
  746. //-----------------------------------------------------------------------
  747.  
  748. static OSErr
  749. GetPrefsDirVRefNumAndDirID (ConstStr31Param folderName, 
  750.     Boolean createFolder, short *vRefNum, long *dirID)
  751. {
  752.     OSErr    result = noErr;
  753.     
  754.     // Make sure parameters are valid
  755.     if ((vRefNum != nil) && (dirID != nil))
  756.     {
  757.         long    id;
  758.         
  759.         // Locate the Preferences folder
  760.         result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  761.             vRefNum, &id);
  762.         if (result == fnfErr)
  763.         {
  764.             // No Preferences folder found, try to find the System Folder
  765.             result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  766.                 vRefNum, &id);
  767.             if (result != noErr)
  768.             {
  769.                 // Couldn't find the System Folder - we're hosed
  770.                 DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
  771.                 goto BAIL;
  772.             }
  773.         }
  774.         else if (result != noErr)
  775.         { 
  776.             // Got some other kind of bad error from FindFolder when trying
  777.             // to find the Preferences folder
  778.             DebugMessage (GetPrefsDirVRefNumAndDirID: FindFolder failed.);
  779.             goto BAIL;
  780.         }
  781.         
  782.         // Are we using a custom preferences folder?
  783.         if (folderName != nil)
  784.         {
  785.             DirInfo    info;
  786.             
  787.             // See if the specified custom preferences folder is around
  788.             info.ioNamePtr = (StringPtr) folderName;
  789.             info.ioVRefNum = *vRefNum;
  790.             info.ioDrDirID = id;
  791.             info.ioFDirIndex = 0;
  792.             result = PBGetCatInfoSync((CInfoPBPtr)&info);
  793.             if (result == noErr)
  794.             {
  795.                 *dirID = info.ioDrDirID;
  796.             }
  797.             else if ((result == fnfErr) && createFolder)
  798.             {
  799.                 // Try to create the specified custom preferences folder
  800.                 result = DirCreate (*vRefNum, id, folderName, dirID);
  801.                 FailMessage (result != noErr, GetPrefsDirVRefNumAndDirID: DirCreate failed.);
  802.             }
  803.             else    // PBGetCatInfo failed
  804.             {
  805.                 DebugMessage (GetPrefsDirVRefNumAndDirID: PBGetCatInfo failed.);
  806.             }
  807.         }
  808.         else    // Not using a custom preferences folder
  809.         {
  810.             *dirID = id;
  811.         }
  812.     }
  813.     else    // Bad parameter
  814.     {
  815.         result = paramErr;
  816.         DebugMessage (GetPrefsDirVRefNumAndDirID: Bad parameter.);
  817.     }
  818.     
  819. BAIL:
  820.     return (result);
  821. }
  822.  
  823. //-----------------------------------------------------------------------
  824.  
  825. static OSErr
  826. GetPreferencesFileFSSpec (OSType creator, OSType fileType,
  827.     FSSpec *file)
  828. {
  829.     OSErr    result = noErr;
  830.     
  831.     // Make sure parameters are valid
  832.     if (file != nil)
  833.     {
  834.         long    systemFolderDirID;
  835.         long    prefsFolderDirID;
  836.         short    vRefNum;
  837.         Boolean    hasPrefsDir;
  838.         Boolean    foundIt = false;
  839.         
  840.         // Find the Preferences folder dirID
  841.         result = FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  842.             &vRefNum, &prefsFolderDirID);
  843.         hasPrefsDir = (result == noErr);
  844.         
  845.         // Find the System Folder dirID
  846.         result = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
  847.             &vRefNum, &systemFolderDirID);
  848.             
  849.         // Did we find the System Folder OK?
  850.         if (result == noErr)
  851.         {
  852.             FSSpec    possibleMatch;
  853.             long    numMatches;
  854.             Boolean    firstSearch = true;
  855.             
  856.             // Check the Preferences folder first
  857.             if (hasPrefsDir)
  858.             {
  859.                 // Loop through the possible candidates until a candidate is found
  860.                 do
  861.                 {
  862.                     result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType, 
  863.                         (FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
  864.                         
  865.                     firstSearch = false;
  866.                     
  867.                     // Did we get a match?
  868.                     if (numMatches == 1)
  869.                     {
  870.                         // Check to see if this file is within the Preferences
  871.                         // folder or any of its nested folders
  872.                         if (DirIDInPrefsDir (vRefNum, possibleMatch.parID, prefsFolderDirID))
  873.                         {
  874.                             // Got one!
  875.                             foundIt = true;
  876.                             break;
  877.                         }
  878.                     }
  879.                 }
  880.                 while ((result == noErr) || (result == catChangedErr));
  881.             }
  882.             
  883.             // If we didn't find it in the Preferences folder, check the
  884.             // System Folder
  885.             if (!foundIt)
  886.             {
  887.                 // Loop through the possible candidates until a candidate is found
  888.                 firstSearch = true;
  889.                 do
  890.                 {
  891.                     result = CreatorTypeFileSearch (nil, vRefNum, creator, fileType, 
  892.                         (FSSpecPtr) &possibleMatch, 1L, &numMatches, firstSearch);
  893.                         
  894.                     firstSearch = false;
  895.                     
  896.                     // Did we get a match?
  897.                     if ((numMatches == 1) && (possibleMatch.parID == systemFolderDirID))
  898.                     {
  899.                         // Got one!
  900.                         foundIt = true;
  901.                         break;
  902.                     }
  903.                 }
  904.                 while ((result == noErr) || (result == catChangedErr));
  905.             }
  906.             
  907.             // If we found one, return it
  908.             if (foundIt)
  909.             {
  910.                 *file = possibleMatch;
  911.             }
  912.             else    // Didn't find a preferences file with the specified creator and file type
  913.             {
  914.                 result = fnfErr;
  915.                 DebugMessage (GetPreferencesFileFSSpec: Could not find preferences file.);
  916.             }
  917.         }
  918.         else    // Couldn't find the System Folder
  919.         {
  920.             DebugMessage (GetPreferencesFileFSSpec: FindFolder failed.);
  921.         }
  922.     }
  923.     else    // Bad parameter
  924.     {
  925.         result = paramErr;
  926.         DebugMessage (GetPreferencesFileFSSpec: Bad parameter.);
  927.     }
  928.     return (result);
  929. }
  930.  
  931. //-----------------------------------------------------------------------
  932.  
  933. static Boolean
  934. DirIDInPrefsDir (short vRefNum, long dirID, long prefsDirID)
  935. {
  936.     OSErr    result = noErr;
  937.     Boolean    inPrefsDir = false;
  938.     
  939.     // Make sure parameters are valid
  940.     if (vRefNum < 0)
  941.     {
  942.         // Is the dirID of the directory the same as the Preferences 
  943.         // folder dirID?
  944.         if (dirID == prefsDirID)
  945.         {
  946.             inPrefsDir = true;
  947.         }
  948.         else    // Nope, we need to follow the path up toward the root
  949.         {
  950.             DirInfo    info;
  951.             Str255    dirName;
  952.             Str255    pathName;
  953.             
  954.             // Initialize some stuff
  955.             
  956.             pathName[0] = '¥0';
  957.         
  958.             info.ioDrParID = dirID;
  959.             info.ioNamePtr = dirName;
  960.             
  961.             // Walk the path upward, one directory at a time,
  962.             // until we either determine that the directory is
  963.             // in the Preferences folder, or until we hit the
  964.             // root directory (this always has a dirID of 2)
  965.             do
  966.             {
  967.                 info.ioVRefNum = vRefNum;
  968.                 info.ioFDirIndex = -1;
  969.                 info.ioDrDirID = info.ioDrParID;
  970.                 result = PBGetCatInfoSync((CInfoPBPtr)&info);
  971.                 if (result == noErr)
  972.                 {
  973.                     // Is this the Preferences folder?
  974.                     if (info.ioDrParID == prefsDirID)
  975.                     {
  976.                         // Yep, we can leave now
  977.                         inPrefsDir = true;
  978.                         break;
  979.                     }
  980.                     else    // Nope, append this string to the path name and try again
  981.                     {
  982.                         result = CatenateStrings (dirName, "¥p:", dirName);
  983.                         if (result == noErr)
  984.                         {
  985.                             result = CatenateStrings (dirName, pathName, pathName);
  986.                             if (result != noErr)
  987.                             {
  988.                                 // CatenateStrings failed
  989.                                 break;
  990.                             }
  991.                         }
  992.                         else    // CatenateStrings failed
  993.                         {
  994.                             break;
  995.                         }
  996.                     }
  997.                 }
  998.                 else    // PBGetCatInfo failed
  999.                 {
  1000.                     DebugMessage (DirIDInPrefsDir: PBGetCatInfo failed.);
  1001.                     break;
  1002.                 }
  1003.             }
  1004.             while (info.ioDrDirID != 2);
  1005.         }
  1006.     }
  1007.     else    // Bad parameter
  1008.     {
  1009.         DebugMessage (DirIDInPrefsDir: Bad parameter.);
  1010.     }
  1011.     return (inPrefsDir);
  1012. }
  1013.  
  1014. //-----------------------------------------------------------------------
  1015.  
  1016. static short
  1017. FindVRefNum (short fRefNum)
  1018. {
  1019.     OSErr    result = noErr;
  1020.     short    vRefNum = 0;
  1021.     
  1022.     // Make sure parameters are valid
  1023.     if (fRefNum != -1)
  1024.     {
  1025.         FCBPBRec    fcbInfo;
  1026.         Str63        fName;
  1027.     
  1028.         // Set up parameter block
  1029.         fcbInfo.ioNamePtr = fName;
  1030.         fcbInfo.ioVRefNum = 0;
  1031.         fcbInfo.ioRefNum = fRefNum;
  1032.         fcbInfo.ioFCBIndx = 0;
  1033.         result = PBGetFCBInfoSync (&fcbInfo);
  1034.         if (result == noErr)
  1035.         {
  1036.             vRefNum = fcbInfo.ioFCBVRefNum;
  1037.         }
  1038.         else    // PBGetFCBInfoSync failed
  1039.         {
  1040.             DebugMessage (FindVRefNum: PBGetFCBInfoSync failed.);
  1041.         }
  1042.     }
  1043.     else    // Bad parameter
  1044.     {
  1045.         DebugMessage (FindVRefNum: Bad parameter.);
  1046.     }
  1047.     return (vRefNum);
  1048. }
  1049.  
  1050. //-----------------------------------------------------------------------
  1051.  
  1052. static unsigned long
  1053. GetVolFreeSpace (short vRefNum)
  1054. {
  1055.     HParamBlockRec    pb;
  1056.     OSErr            result = noErr;
  1057.  
  1058.     pb.volumeParam.ioNamePtr = nil;            // We don't care about the name
  1059.     pb.volumeParam.ioVRefNum = vRefNum;
  1060.     pb.volumeParam.ioVolIndex = 0;            // Use ioVRefNum only
  1061.     result = PBHGetVInfoSync(&pb);
  1062.  
  1063.     if (result == noErr)
  1064.     {
  1065.         // Calculate the free space in bytes
  1066.         return (pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz);
  1067.     }
  1068.     else    // PBHGetVInfo failed
  1069.     {
  1070.         DebugMessage (GetVolFreeSpace: PBHGetVInfo failed.);
  1071.         return (0L);
  1072.     }
  1073. }
  1074.  
  1075. //-----------------------------------------------------------------------
  1076.  
  1077. static unsigned long
  1078. GetVAllocationBlockSize (short vRefNum)
  1079. {
  1080.     HParamBlockRec    pb;
  1081.     OSErr            result = noErr;
  1082.     
  1083.     pb.volumeParam.ioNamePtr = nil;        // We don't care about the name
  1084.     pb.volumeParam.ioVRefNum = vRefNum;    
  1085.     pb.volumeParam.ioVolIndex = 0;        // Use ioVRefNum only
  1086.     result = PBHGetVInfoSync(&pb);
  1087.     
  1088.     if (result == noErr)
  1089.     {
  1090.         return (pb.volumeParam.ioVAlBlkSiz);
  1091.     }
  1092.     else
  1093.     {
  1094.         return (0L);
  1095.     }
  1096. }
  1097.  
  1098. //-----------------------------------------------------------------------
  1099.  
  1100. static OSErr
  1101. GetDirPathName (short vRefNum, long dirID, Str255 pathName)
  1102. {
  1103.     OSErr    result = noErr;
  1104.     
  1105.     // Make sure parameters are valid
  1106.     if (vRefNum < 0)
  1107.     {
  1108.         DirInfo    info;
  1109.         Str255    dirName;
  1110.         
  1111.         // Initialize some stuff
  1112.         
  1113.         pathName[0] = '¥0';
  1114.     
  1115.         info.ioDrParID = dirID;
  1116.         info.ioNamePtr = dirName;
  1117.         
  1118.         // Walk the path upward, one directory at a time,
  1119.         // until we hit the root directory (this always 
  1120.         // has a dirID of 2)
  1121.         do
  1122.         {
  1123.             info.ioVRefNum = vRefNum;
  1124.             info.ioFDirIndex = -1;
  1125.             info.ioDrDirID = info.ioDrParID;
  1126.             result = PBGetCatInfoSync((CInfoPBPtr)&info);
  1127.             if (result == noErr)
  1128.             {
  1129.                 result = CatenateStrings (dirName, "¥p:", dirName);
  1130.                 if (result == noErr)
  1131.                 {
  1132.                     result = CatenateStrings (dirName, pathName, pathName);
  1133.                     if (result != noErr)
  1134.                     {
  1135.                         // CatenateStrings failed
  1136.                         break;
  1137.                     }
  1138.                 }
  1139.                 else    // CatenateStrings failed
  1140.                 {
  1141.                     break;
  1142.                 }
  1143.             }
  1144.             else    // PBGetCatInfo failed
  1145.             {
  1146.                 DebugMessage (GetDirPathName: PBGetCatInfo failed.);
  1147.                 break;
  1148.             }
  1149.         }
  1150.         while (info.ioDrDirID != 2);
  1151.     }
  1152.     else    // Bad parameter
  1153.     {
  1154.         result = paramErr;
  1155.         DebugMessage (GetDirPathName: Bad parameter.);
  1156.     }
  1157.     return (result);
  1158. }
  1159.  
  1160. //-----------------------------------------------------------------------
  1161.  
  1162. static OSErr
  1163. CopyString (ConstStr255Param theSourceStr, Str255 theDestStr)
  1164. {
  1165.     OSErr    result = noErr;
  1166.  
  1167.     // Make sure parameters are valid
  1168.     if ((theSourceStr != nil) && (theDestStr != nil))
  1169.     {
  1170.         BlockMoveData ((Ptr)theSourceStr, (Ptr)theDestStr, theSourceStr[0] + 1);
  1171.     }
  1172.     else    // Bad parameter
  1173.     {
  1174.         result = paramErr;
  1175.         DebugMessage (StrCopy: Bad parameter.);
  1176.     }
  1177.     return (result);
  1178. }
  1179.  
  1180. //-----------------------------------------------------------------------
  1181.  
  1182. static OSErr
  1183. CatenateStrings (ConstStr255Param theFirstStr,
  1184.     ConstStr255Param theSecondStr, Str255 theCatenatedStr)
  1185. {
  1186.     OSErr    result = noErr;
  1187.     
  1188.     // Make sure parameters are valid
  1189.     if ((theFirstStr != nil) && (theSecondStr != nil) && 
  1190.         (theCatenatedStr != nil))
  1191.     {
  1192.         Str255    catenatedStr;
  1193.         Str255    secondStr;
  1194.         long    tempSize;
  1195.         short    combinedLength = theFirstStr[0] + theSecondStr[0];
  1196.         short    secondStrLength = theSecondStr[0];
  1197.         
  1198.         // Can both strings fit in a Str255?
  1199.         if (combinedLength > 255)
  1200.         {
  1201.             // Nope, let's shorten the second string to fit
  1202.             secondStrLength = 255 - theFirstStr[0];
  1203.         }
  1204.  
  1205.         // Copy the strings
  1206.         BlockMoveData ((Ptr)theFirstStr, (Ptr)catenatedStr, theFirstStr[0] + 1);
  1207.         BlockMoveData ((Ptr)theSecondStr, (Ptr)secondStr, secondStrLength + 1);
  1208.     
  1209.         // Copy the second string to the end of the first string
  1210.         tempSize = catenatedStr[0];
  1211.         catenatedStr[0] += secondStr[0];
  1212.         BlockMoveData ((Ptr)&secondStr[1], (Ptr)&catenatedStr[tempSize + 1], 
  1213.             secondStr[0]);
  1214.         
  1215.         // Copy the catenated string back out
  1216.         BlockMoveData ((Ptr)catenatedStr, (Ptr)theCatenatedStr, 
  1217.             catenatedStr[0] + 1);
  1218.     }
  1219.     else    // Bad parameter
  1220.     {
  1221.         result = paramErr;
  1222.         DebugMessage (StrCatenate: Bad parameter.);
  1223.     }
  1224.     return (result);
  1225. }
  1226.  
  1227. //-----------------------------------------------------------------------
  1228.  
  1229. static OSErr
  1230. CopyResource (ResType theType, short theID, FSSpec *fileToCopyTo)
  1231. {
  1232.     OSErr    result = noErr;
  1233.     
  1234.     // Make sure parameters are valid
  1235.     if (fileToCopyTo != nil)
  1236.     {
  1237.         Handle    resToBeCopied = GetResource (theType, theID);
  1238.         short    appResRefNum;
  1239.         
  1240.         if ((result = ResError()) == noErr)
  1241.         {
  1242.             // Get the application's resource refNum
  1243.             appResRefNum = LMGetCurApRefNum();
  1244.             if ((resToBeCopied != nil) &&
  1245.                 (appResRefNum == HomeResFile (resToBeCopied)))
  1246.             {
  1247.                 Handle    resToCopyTo;
  1248.                 short    resAttributes;
  1249.                 short    copyToFileResRefNum;
  1250.                 short    savedResFile = CurResFile();
  1251.                 
  1252.                 // Get the attributes of the resource to be copied
  1253.                 resAttributes = GetResAttrs (resToBeCopied);
  1254.                 
  1255.                 // Detach the resource to be coped
  1256.                 DetachResource (resToBeCopied);
  1257.                 if ((result = ResError()) == noErr)
  1258.                 {
  1259.                     // Open the file to copy to
  1260.                     copyToFileResRefNum = FSpOpenResFile (fileToCopyTo, fsRdWrPerm);
  1261.                     if ((result = ResError()) == noErr)
  1262.                     {
  1263.                         // Set the resource refNum
  1264.                         UseResFile (copyToFileResRefNum);
  1265.                         
  1266.                         // Check for existing resources with this type and ID in
  1267.                         // the file we're copying to, and remove any we find
  1268.                         do
  1269.                         {
  1270.                             // Get a resource
  1271.                             resToCopyTo = GetResource (theType, theID);
  1272.  
  1273.                             // Is the resource's res file the same as the
  1274.                             // file we're trying to copy to?
  1275.                             if (HomeResFile (resToCopyTo) == copyToFileResRefNum)
  1276.                             {
  1277.                                 // Remove it
  1278.                                 RemoveResource (resToCopyTo);
  1279.                                 FailMessage ((result = ResError()) != noErr, CopyResource: RmveResource failed.);
  1280.                                 DisposeHandle (resToCopyTo);
  1281.                                 FailMessage ((result = MemError()) != noErr, CopyResource: DisposeHandle failed.);
  1282.                             }
  1283.                         }
  1284.                         while (HomeResFile (resToCopyTo) != copyToFileResRefNum);
  1285.                         
  1286.                         // Add the resource
  1287.                         AddResource (resToBeCopied, theType, theID, "¥p");
  1288.                         if ((result = ResError()) == noErr)
  1289.                         {
  1290.                             // Set up the resource's attributes
  1291.                             SetResAttrs (resToBeCopied, resAttributes);
  1292.                             ChangedResource (resToBeCopied);
  1293.                             FailMessage ((result = ResError()) != noErr, CopyResource: ChangedResource failed.);
  1294.                         }
  1295.                         
  1296.                         // Close the file
  1297.                         CloseResFile (copyToFileResRefNum);
  1298.                         
  1299.                         // Restore resource file
  1300.                         UseResFile (savedResFile);
  1301.                     }
  1302.                     else    // FSpOpenResFile failed
  1303.                     {
  1304.                         DebugMessage (CopyResource: FSpOpenResFile failed.);
  1305.                     }
  1306.                 }
  1307.                 else    // DetachResource failed
  1308.                 {
  1309.                     DebugMessage (CopyResource: DetachResource failed.);
  1310.                 }
  1311.             }
  1312.         }
  1313.         else    // GetResource failed
  1314.         {
  1315.             DebugMessage (CopyResource: GetResource failed.);
  1316.         }
  1317.     }
  1318.     else    // Bad parameter
  1319.     {
  1320.         result = paramErr;
  1321.         DebugMessage (CopyResource: Bad parameter.);
  1322.     }
  1323.     return (result);
  1324. }
  1325.  
  1326. //-----------------------------------------------------------------------
  1327.  
  1328.  
  1329.  
  1330.